package fr.pud.client.model;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.Serializable;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Observable;
import java.util.Set;

import fr.pud.client.i18n.LanguagesConstants;
import fr.pud.client.view.MapQueries;
import fr.pud.utils.Tools;

/**
 * The set of queries which could represent a sort of database.
 * Apr 9, 2012 - OSE.
 * @author Simon Devineau, Adrien Hierry, Leopold Houdin, Pierre Reliquet
 *         Ecole des Mines de Nantes
 *         Queries.java
 */
public class Queries extends Observable implements Serializable,
        Iterable<Query> {
    /**
     * The serial UID
     */
    private static final long serialVersionUID = 4768430490664733991L;
    /**
     * The singleton implementation
     */
    private static Queries    singleton        = null;

    /**
     * @return the singleton
     */
    public static Queries getInstance() {
        initialize();
        return singleton;
    }

    /**
     * The method to initialize the singleton.
     */
    private static void initialize() {
        if (singleton == null) {
            singleton = new Queries();
            singleton.addObserver(PUDStationDatabase.getInstance());
        }
    }

    /**
     * Load a Queries
     * @return an arrayList of query
     */
    @SuppressWarnings("unchecked")
    public static Set<Query> loadObject(File aFile) {
        Set<Query> toReturn = null;
        if (aFile.exists()) {
            try {
                FileInputStream fis = new FileInputStream(aFile);
                ObjectInputStream ois = new ObjectInputStream(fis);
                try {
                    toReturn = (Set<Query>) ois.readObject();
                }
                finally {
                    try {
                        ois.close();
                    }
                    finally {
                        fis.close();
                    }
                }
            }
            catch (IOException ioe) {
                Tools.writeToLogFile(
                        LanguagesConstants.LANGUAGE
                                .getString(LanguagesConstants.ERROR_FILE)
                                + " : " + aFile, true, ioe.getStackTrace());
            }
            catch (ClassNotFoundException cnfe) {
                Tools.writeToLogFile(
                        LanguagesConstants.LANGUAGE
                                .getString(LanguagesConstants.ERROR_FILE)
                                + " : " + aFile, true, cnfe.getStackTrace());
            }
        }
        return toReturn;
    }

    /**
     * The set of queries
     */
    private Set<Query> queries = new HashSet<Query>();

    private Queries() {
        this.addObserver(MapQueries.getInstance());
    }

    /**
     * @param aQuery
     *            the query to add.
     */
    public void addQuery(Query aQuery) {
        initialize();
        this.queries.add(aQuery);
        this.setChanged();
        this.notifyObservers(aQuery);
    }

    /**
     * @return the queries
     */
    public Set<Query> getQueries() {
        initialize();
        return this.queries;
    }

    /**
     * The iterator on the Queries database.
     */
    @Override
    public Iterator<Query> iterator() {
        initialize();
        return this.queries.iterator();
    }

    /**
     * @param index
     *            the index of the element to remove.
     * @return true if the element was removed.
     */
    public boolean remove(int index) {
        initialize();
        if (!this.queries.remove(index)) {
            this.setChanged();
            this.notifyObservers();
            return true;
        }
        return false;
    }

    /**
     * @param v
     *            the vehicle to remove
     * @return true if the vehicle has been removed.
     */
    public boolean removeQuery(Query q) {
        initialize();
        if (this.queries.remove(q)) {
            this.setChanged();
            this.notifyObservers();
            return true;
        }
        return false;
    }

    /**
     * Notify the observer that a query has changed after the using of
     * Query.set...
     */
    public void setQueries() {
        this.setChanged();
        this.notifyObservers();
    }

    /**
     * @param queries
     *            the new queries.
     */
    public void setQueries(Set<Query> queries) {
        initialize();
        for (Query oldQuery : queries) {
            this.removeQuery(oldQuery);
        }
        for (Query newQuery : queries) {
            this.addQuery(newQuery);
        }
    }

    @Override
    public String toString() {
        String toReturn = "";
        for (Query r : this.queries) {
            toReturn += r + "\n";
        }
        return toReturn;
    }
}
